/**
 * Copyright (c) 2022 Presto Labs Pte. Ltd.
 * Author: Ju
 */

#include "coin2/base/tcp/tcp_server.h"

#include <glog/logging.h>

namespace coin2::base::tcp {

TcpServer::TcpServer(boost::asio::io_context* ioc, uint16_t port,
                     Callback* callback)
    : ioc_(ioc),
      strand_(*ioc_),
      callback_(callback),
      port_(port),
      acceptor_(*ioc_, tcp::endpoint(tcp::v4(), port)),
      running_(false) {}

TcpServer::~TcpServer() { Close(); }

void TcpServer::Close() {
  running_ = false;
  if (acceptor_.is_open()) {
    acceptor_.close();
  }
}

void TcpServer::ReusePort(bool reuse_port) {
  acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(reuse_port));
}

void TcpServer::RunAsync() {
  running_ = true;
  boost::asio::spawn(strand_, [this](boost::asio::yield_context yield) {
    while (running_) {
      auto conn = std::make_shared<TcpConnection>(ioc_);
      boost::system::error_code ec;
      acceptor_.async_accept(conn->Socket(), yield[ec]);
      if (ec) {
        LOG(ERROR) << "[TcpServer Error] accceptor error.";
        Close();
        callback_->OnError(ec);
      } else {
        LOG(INFO) << "Tcp Connection success!" << conn->Ip() << ":"
                  << conn->Port();
        callback_->OnAccept(conn);
        conn->Start();
      }
    }
  });
}

}  // namespace coin2::base::tcp